package edu.mercer.sse661.ao;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

import com.google.common.base.Throwables;
import com.google.common.hash.HashCode;

import static com.google.common.base.Preconditions.*;

/**
 * Active Object Pattern Demonstration: Scheduler and Servant implementation.
 * <p>
 * 
 * Integrated Scheduler-Servant.<p>
 * 
 * Single thread dedicated in Proxy runs this Scheduler.<p>
 * 
 * Tasks are executed asynchronously in new threads, functioning as Servant.
 * <p>
 *
 * BlockingQueue's provide guarded exchange of download tasks and Future's 
 * 	between Proxy and Scheduler-Servant.<p>
 * 
 * Proxy reference and HashCode provided to constructor. Used for mutable 
 * 	access Proxy's BlockingQueue's.<p>
 *
 * Uses AutoCloseable to shutdown executor threadpool used to execute download 
 * 	tasks concurrently.
 *
 * @see WebRetrieval
 * @see Runnable
 * @see AutoCloseable
 */

public class WebRetrievalScheduler implements Runnable
{
	/**
	 * Threadpool used to execute download tasks.
	 */

	private final ExecutorService _exeMultiSvc = Executors
			.newCachedThreadPool();
	
	
	/**
	 * Proxy instance.<p>
	 * 
	 * Used to access BlockingQueue's for new download tasks and output of 
	 * 	Future's from started tasks.<p>
	 */
	
	private WebsiteRetrieval _websiteRetrieval;


	/**
	 * HashCode for Proxy instance.<p>
	 * 
	 * Used by Proxy to restrict access to BlockingQueue's get/set methods, 
	 * 	limiting to this WebRetrievalScheduler only.<p>
	 * 
	 * @see HashCode
	 */
	
	private HashCode _hashCode;
	
	
	/**
	 * Constructor.<p>
	 * 
	 * Receives Proxy instance and HashCode object. Used to access 
	 * 	BlockingQueue's held within Proxy.<p>
	 * 
	 * @param websiteRetrieval - Proxy instance
	 * 
	 * @param hashCode - HashCode of Proxy instance
	 * 
	 * @see HashCode
	 */
	
	WebRetrievalScheduler( final WebsiteRetrieval websiteRetrieval, 
						   final HashCode hashCode )
	{
		super();
		
		checkNotNull( websiteRetrieval, "null proxy instance" );
		
		checkNotNull( hashCode, "null HashCode" );
		
		_websiteRetrieval = websiteRetrieval;
		
		_hashCode = hashCode;
		
	}//constructor

	
	/**
	 * Scheduler processing loop.<p>
	 * 
	 * Monitors for new tasks added to Proxy.<p>
	 */
	
	public void run()
	{
		final Integer timeOut = WebsiteRetrieval._maxWait;
		final TimeUnit unit = TimeUnit.SECONDS;
		
		while( true )
		{
			try
			{			
				if( ! _websiteRetrieval.getTasks(_hashCode).isEmpty() )
				{
					LoggerCustom.obtainLog( "website_retrieval_scheduler", 
							Level.ALL).fine( "processing newfound task"); 


					DownloadURL task = _websiteRetrieval.getTasks(_hashCode)
														.poll(timeOut, unit);
					
					Future<StringBuilder> result = _exeMultiSvc.submit(task);
					
					_websiteRetrieval.getResults(_hashCode)
						 			 .put( result );

				}//if
			}
			catch( final InterruptedException err )
			{
				throw new RuntimeException( "timeout waiting on retrieval of "
						+ "download task from queue: " 
						+ " " 
						+ Throwables.getStackTraceAsString(err) );			

			}//try			
				
		}//while
		
	}//method	
	

	/**
	 * Shutdown threadpool used as Servant to execute tasks concurrently in 
	 * 	new threads.<p>
	 */
	
	public void close()
	{
		_exeMultiSvc.shutdown();
		
	}//method
	
	
}//class
